home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 15
/
Aminet 15 - Nov 1996.iso
/
Aminet
/
dev
/
lang
/
FPL_v147.lha
/
fpl
/
src
/
statement.c
< prev
Wrap
C/C++ Source or Header
|
1996-08-06
|
50KB
|
2,015 lines
/******************************************************************************
* FREXX PROGRAMMING LANGUAGE *
******************************************************************************
statement.c
Support routines to the Expression() function.
*****************************************************************************/
/************************************************************************
* *
* fpl.library - A shared library interpreting script langauge. *
* Copyright (C) 1992-1994 FrexxWare *
* Author: Daniel Stenberg *
* *
* This program is free software; you may redistribute for non *
* commercial purposes only. Commercial programs must have a written *
* permission from the author to use FPL. FPL is *NOT* public domain! *
* Any provided source code is only for reference and for assurance *
* that users should be able to compile FPL on any operating system *
* he/she wants to use it in! *
* *
* You may not change, resource, patch files or in any way reverse *
* engineer anything in the FPL package. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
* Daniel Stenberg *
* Ankdammsgatan 36, 4tr *
* S-171 43 Solna *
* Sweden *
* *
* FidoNet 2:201/328 email:dast@sth.frontec.se *
* *
************************************************************************/
#ifdef AMIGA
#include <exec/types.h>
#include <proto/exec.h>
#include <stdlib.h>
#include <proto/dos.h>
#include <exec/execbase.h>
#include <dos.h>
#include "/funclib/funclib.h"
#else
#include <sys/types.h>
#ifdef SUNOS
#include <varargs.h>
#else
#include <stdarg.h>
#endif
#endif
#include "script.h"
#include "debug.h"
#include <stdio.h>
#include <stddef.h>
#include <limits.h>
static ReturnCode INLINE SendMessage(struct Data *, struct fplMsg *);
static ReturnCode REGARGS Ltostr(struct Data *scr, struct fplStr **,
long, long);
static ReturnCode REGARGS GetSymbols(struct Data *, long, long,
struct fplSymbol **);
/**********************************************************************
*
* ReturnCode CmpAssign()
*
* Performs a compound assign to the value the third argument points to.
* The assign performed is the one with the operator specified in the fourth
* argument eg, x, +, /, &, %, | etc, etc...
*
***************/
ReturnCode REGARGS
CmpAssign(struct Data *scr,
long val, /* right operand */
long *value, /* return value pointer */
long flags, /* variable flags */
uchar operation)
{
ReturnCode ret;
switch(operation) { /* check the type of the assign */
case CHAR_PLUS:
*value+=val;
break;
case CHAR_MINUS:
*value-=val;
break;
case CHAR_MULTIPLY:
*value*=val;
break;
case CHAR_DIVIDE:
*value/=val;
break;
case CHAR_AND:
*value&=val;
break;
case CHAR_OR:
*value|=val;
break;
case CHAR_REMAIN:
*value%=val;
break;
case CHAR_XOR:
*value^=val;
break;
case CHAR_LESS_THAN:
*value<<=val;
break;
case CHAR_GREATER_THAN:
*value>>=val;
break;
case CHAR_ASSIGN:
*value=val;
break;
default:
CALL(Warn(scr, FPLERR_ILLEGAL_ASSIGN)); /* >warning< */
*value=val; /* perform a straight assign! */
break;
}
if(flags&FPL_VARIABLE_LESS32) {
/* if using less than 32 bit */
if(flags&FPL_CHAR_VARIABLE)
*value=(long)((signed char)*value);
else
*value=(long)((signed short)*value);
}
return(FPL_OK);
}
/**********************************************************************
*
* StrAssign();
*
* Assign a string variable.
*
********/
ReturnCode REGARGS
StrAssign(struct fplStr *app,
struct Data *scr,
struct fplStr **string,
uchar append) /* TRUE or FALSE if append */
{
ReturnCode ret;
if(!append) { /* if not append */
/* Exchange this string with the old one in the variable! */
if(*string) {
/*
* There is a string! Free any type!
*/
FREE_KIND(*string);
}
if(!app) {
GETMEM(app, sizeof(struct fplStr));
memset(app, 0, sizeof(struct fplStr)); /* clean it! */
}
*string = app;
} else { /* append string */
if(! (app?app->len:0))
/* we don't append zero length strings! */
return FPL_OK;
CALL(AppendStringToString(scr, string, app->string, app->len));
}
return(FPL_OK);
}
/************************************************************************
*
* AppendStringToString()
*
* Append a generic string to a fplStr.
*
*/
ReturnCode REGARGS
AppendStringToString(struct Data *scr, /* common data struct */
struct fplStr **string, /* variable to append to */
uchar *append, /* string to append */
long applen) /* length of append string */
{
long length;
long alloc;
long ln;
struct fplStr *pek;
ReturnCode ret;
void *dest;
uchar type = *string?TypeMem(*string):MALLOC_DYNAMIC;
length=*string?(*string)->len:0;
alloc=*string?(*string)->alloc:0;
ln = applen + length; /* total length */
if (ln>=alloc) { /* do we have that much memory allocated? */
/*
* Allocate new memory for string.
*/
GETMEM(pek, sizeof(struct fplStr)+ln+ADDSTRING_INC);
if(MALLOC_STATIC == type)
SwapMem(scr, pek, MALLOC_STATIC);
if(*string) {
memcpy(pek, (*string), length+sizeof(struct fplStr));
FREE_KIND(*string);
} else
pek->len=0;
#ifdef DEBUG
CheckMem(scr, pek);
#endif
(*string)=pek; /* the new pointer */
(*string)->alloc=ln+ADDSTRING_INC; /* new allocated size */
}
dest=(void *)&(*string)->string[length];
/* no string function... only mem-versions! */
memcpy(dest, (void *)append, applen);
(*string)->len += applen;
(*string)->string[(*string)->len]=CHAR_ASCII_ZERO; /* zero terminate */
return FPL_OK;
}
/************************************************************************
*
* ReturnChar()
*
* Returns the ASCII code of the character scr->text points to.
*
* Supports 100% ANSI C escape sequences.
*/
ReturnCode REGARGS
ReturnChar(struct Data *scr,
long *num,
uchar string) /* is this is within quotes */
{
ReturnCode ret=FPL_OK;
long cont=TRUE, steps;
*num=256;
while(cont) {
cont=FALSE;
if(*scr->text==CHAR_BACKSLASH) {
steps=2;
switch(scr->text[1]) {
case CHAR_B:
*num=CHAR_BACKSPACE;
break;
case CHAR_T:
*num=CHAR_TAB;
break;
case CHAR_N:
*num=CHAR_NEWLINE;
break;
case CHAR_F:
*num=CHAR_FORMFEED;
break;
case CHAR_BACKSLASH:
*num=CHAR_BACKSLASH;
break;
case CHAR_QUOTATION_MARK:
*num=CHAR_QUOTATION_MARK;
break;
case CHAR_APOSTROPHE:
*num=CHAR_APOSTROPHE;
break;
case CHAR_A:
*num=CHAR_ALERT;
/* ^^^^ causes warnings ('warning: \a is ANSI C "alert" character')
* on some compilers. Ignore and look happy!
*/
break;
case CHAR_R:
*num=CHAR_CARRIAGE_RETURN;
break;
case CHAR_V:
*num=CHAR_VERTICAL_TAB;
break;
case CHAR_QUESTION:
*num=CHAR_QUESTION;
break;
case CHAR_X:
steps=*num=0;
for(scr->text+=2; steps++<2 && isxdigit(*scr->text); scr->text++)
*num=*num*16+ (isdigit(*scr->text)?
*scr->text-CHAR_ZERO:
UPPER(*scr->text)-CHAR_UPPER_A+10);
if(!steps)
return(FPLERR_SYNTAX_ERROR); /* no number followed \x sequence */
steps=0;
break;
case CHAR_ZERO:
case CHAR_ONE:
case CHAR_TWO:
case CHAR_THREE:
case CHAR_FOUR:
case CHAR_FIVE:
case CHAR_SIX:
case CHAR_SEVEN:
*num=steps=0;
for(scr->text++;steps++<3 && isodigit(*scr->text);)
*num=*num*8+ *scr->text++ - CHAR_ZERO;
steps=0;
break;
case CHAR_NEWLINE:
/* After a line continuation backslash, a newline is required!
This is made to apply to the ANSI C escape sequence standard.
(added 930113-1305 / DaSt) */
cont=TRUE;
scr->virprg++;
break;
case CHAR_ASCII_ZERO:
/* Added 950603 to make the fplConvertString() work better if the
string to convert ends with a backslash! */
cont=TRUE;
CALL(Newline(scr));
steps=0;
break;
default:
/* Any character not identified as a escape sequence character
will simply ignore the backslah character!
(added 930113-1307 / DaSt) */
*num=scr->text[1];
break;
}
scr->text+=steps;
} else if(!string && *scr->text== CHAR_NEWLINE) {
/* This won't occur if the script is preprocessed! */
cont=TRUE;
scr->text++;
} else if(*scr->text== CHAR_ASCII_ZERO) {
/* This won't occur if the script is preprocessed! */
cont=TRUE;
CALL(Newline(scr));
} else {
*num=*scr->text;
scr->text++;
}
}
return(ret);
}
/**********************************************************************
*
* ReturnCode NewMember(struct Expr **);
*
* This function adds a new member in the linked list which keeps
* track on every operand and it's opertor in the expression.
*
*******/
ReturnCode REGARGS
NewMember(struct Data *scr,
struct Expr **expr)
{
GETMEM((*expr)->next, sizeof(struct Expr));
(*expr)=(*expr)->next;
(*expr)->val.val=0;
(*expr)->unary=NULL;
(*expr)->operator=OP_NOTHING;
(*expr)->flags=FPL_OPERAND;
(*expr)->next=NULL;
return(FPL_OK);
}
/**********************************************************************
*
* ReturnCode Warn();
*
* This routines calls the interface function to ask for permission to
* continue the execution, even though error(s) has/have been found in
* the interpreted program.
*
******/
ReturnCode REGARGS
Warn(struct Data *scr,
ReturnCode rtrn)
{
struct fplArgument *pass;
struct fplMsg *msg;
ReturnCode ret;
GETMEM(pass, sizeof(struct fplArgument));
pass->ID=FPL_WARNING;
pass->key=scr;
pass->argc=1;
pass->argv=(void **)&rtrn; /* first ->argv member holds the error/warning number! */
ret=InterfaceCall(scr, pass, scr->function);
FREE(pass);
GetMessage(scr, FPLMSG_CONFIRM, &msg);
if(msg) {
if(msg->message[0]) {
rtrn=ret;
scr->prog->warnings++;
}
DeleteMessage(scr, msg);
}
return(rtrn);
}
#ifndef AMIGA /* if not using SAS/C on Amiga */
#ifdef VARARG_FUNCTIONS
long fplSendTags(void *anchor, ...)
{
va_list tags;
long ret;
#ifdef SUNOS
va_start(tags); /* get parameter list */
#else
va_start(tags, anchor); /* get parameter list */
#endif
ret = fplSend(anchor, (unsigned long *)tags);
va_end(tags);
return ret;
}
#else
long fplSendTags(void *anchor, unsigned long tags, ...)
{
return(fplSend(anchor, &tags));
}
#endif
#endif
/**********************************************************************
*
* fplSend()
*
* Send a message to FPL.
*
******/
ReturnCode PREFIX fplSend(AREG(0) struct Data *scr,
AREG(1) unsigned long *tags)
{
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_FUNCTION, 500, "fplSend");
#endif
return Send(scr, tags);
}
ReturnCode REGARGS Send(struct Data *scr,
unsigned long *tags)
{
struct fplMsg msg;
long len=-1;
struct Program *prog;
uchar *data=NULL;
ReturnCode ret;
struct fplSymbol *symbol;
struct fplStr *string;
long mixed;
static long *resultcode=NULL;
uchar fplallocstring=FALSE;
if(!scr)
return(FPLERR_ILLEGAL_ANCHOR);
memset(&msg, 0, sizeof(struct fplMsg));
while(tags && *tags) {
switch(*tags++) {
case FPLSEND_STRING:
/* FPLSEND_PROGRAMFILE is the same tag */
data=(void *)*tags;
msg.type=FPLMSG_RETURN;
msg.flags = FPLMSG_FLG_STRING;
break;
case FPLSEND_STRLEN:
len=(long)*tags;
break;
case FPLSEND_DONTCOPY_STRING: /* the string sent is fplAllocString()'ed */
fplallocstring=(uchar)*tags;
break;
case FPLSEND_INT:
msg.message[0]=(void *)*tags;
msg.type=FPLMSG_RETURN;
msg.flags = FPLMSG_FLG_INT;
break;
case FPLSEND_PROGRAM:
msg.message[0]=(void *)*tags;
msg.type=FPLMSG_PROGRAM;
break;
case FPLSEND_CONFIRM:
msg.type=FPLMSG_CONFIRM;
msg.message[0]=(void *)*tags;
break;
case FPLSEND_GETINTERVAL:
*(long *)*tags=(long)scr->interfunc;
break;
case FPLSEND_GETFUNCTION:
*(long *)*tags=(long)scr->function;
break;
case FPLSEND_GETLINE:
*(long *)*tags=scr->prg;
break;
case FPLSEND_GETVIRFILE:
*(uchar **)*tags=scr->virfile;
break;
case FPLSEND_GETVIRLINE:
*(long *)*tags=scr->virprg;
break;
case FPLSEND_GETNEWLINE_HOOK: /* OBSOLETE!!!! */
break;
case FPLSEND_GETRESULT:
*(long *)*tags=scr->data;
break;
case FPLSEND_GETRETURNCODE:
*(long *)*tags=scr->FPLret;
break;
case FPLSEND_GETRETURNINT: /* new from V10 */
*(long **)*tags=scr->returnint;
break;
case FPLSEND_GETUSERDATA:
*(long *)*tags=(long)scr->userdata;
break;
case FPLSEND_GETCOLUMN:
if(scr->prog && scr->prog->running)
*(long *)*tags=(scr->text-(&scr->prog->program)[scr->prg-1]+1);
else if(scr->prog)
/* we cannot count on this programs presence */
*(long *)*tags=scr->prog->column;
else
*(long *)*tags=0; /* we don't know! */
break;
case FPLSEND_GETPROGNAME:
if(scr->prog && scr->prog->name)
*(uchar **)*tags=scr->prog->name;
else /* we have no program information */
*(uchar **)*tags=FPLTEXT_UNKNOWN_PROGRAM;
break;
case FPLSEND_GETPROG:
if(scr->prog && scr->prog->program)
*(uchar **)*tags=scr->prog->program;
else /* we have no program information */
*(uchar **)*tags=NULL;
break;
case FPLSEND_FLUSHCACHE:
if(*tags)
FlushFree(scr);
break;
case FPLSEND_FLUSHFILE:
if(*tags) {
prog=scr->programs;
while(prog) {
if(prog->name && !strcmp(prog->name, (uchar *)*tags))
break;
prog=prog->next;
}
if(!prog)
return(FPLERR_INTERNAL_ERROR);
} else
prog=scr->programs;
while(prog) {
if(!(prog->running)) {
/* if the program isn't running right now! */
len=prog->flags;
prog->flags&=~PR_CACHEFILE; /* switch off the cache bit now */
CALL(LeaveProgram(scr, prog));
prog->flags=len; /* restore flag bits! */
}
if(*tags)
/* only the specified */
break;
prog=prog->next;
}
break;
case FPLSEND_FREEFILE:
prog=scr->programs;
while(prog) {
if(prog->name && !strcmp(prog->name, (uchar *)*tags))
break;
prog=prog->next;
}
if(!prog || prog->running || prog->openings)
/* if not found or if the found one is currently in use! */
return(FPLERR_ILLEGAL_PARAMETER);
{
for(mixed=0; mixed<scr->hash_size; mixed++) {
register struct Identifier *nident;
register struct Identifier *ident = scr->hash[mixed];
while(ident) {
nident=ident->next;
if(!strcmp(ident->file, (uchar *)*tags))
DelIdentifier(scr, NULL, ident);
ident=nident;
}
}
}
DelProgram(scr, prog);
break;
case FPLSEND_STEP:
if(*tags>0) {
while((*tags)--) {
if(!*scr->text)
CALL(Newline(scr));
scr->text++;
}
} else if((signed int)(*tags)<0) {
while((*tags)++) {
if( (scr->text-(&scr->prog->program)[scr->prg-1])>=0)
scr->text--;
else
if(scr->prg>1)
scr->text=(&scr->prog->program)[--scr->prg-1];
else
return(FPLERR_UNEXPECTED_END);
}
}
break;
case FPLSEND_GETSYMBOL_FUNCTIONS:
CALL(GetSymbols(scr, FPL_EXTERNAL_FUNCTION|FPL_INSIDE_FUNCTION,
FPL_EXPORT_SYMBOL,
(struct fplSymbol **)*tags));
break;
case FPLSEND_GETSYMBOL_MYFUNCTIONS:
CALL(GetSymbols(scr, FPL_EXTERNAL_FUNCTION, FPL_FUNCTION,
(struct fplSymbol **)*tags));
break;
case FPLSEND_GETSYMBOL_FPLFUNCTIONS:
CALL(GetSymbols(scr, FPL_EXPORT_SYMBOL, FPL_INSIDE_FUNCTION,
(struct fplSymbol **)*tags));
break;
case FPLSEND_GETSYMBOL_VARIABLES:
CALL(GetSymbols(scr, FPL_EXPORT_SYMBOL, FPL_VARIABLE,
(struct fplSymbol **)*tags));
break;
case FPLSEND_GETSYMBOL_ALLVARIABLES:
CALL(GetSymbols(scr, ~0, FPL_VARIABLE, (struct fplSymbol **)*tags));
break;
case FPLSEND_GETSYMBOL_ALLFUNCTIONS:
CALL(GetSymbols(scr, ~0, FPL_FUNCTION, (struct fplSymbol **)*tags));
break;
case FPLSEND_GETSYMBOL_CACHEDFILES:
prog=scr->programs;
mixed=0;
while(prog) {
if(prog->flags&PR_CACHEFILE)
mixed++;
prog=prog->next;
}
GETMEM(symbol, sizeof(struct fplSymbol));
symbol->num=mixed;
GETMEM(symbol->array, mixed*sizeof(uchar *));
mixed=0;
prog=scr->programs;
while(prog) {
if(prog->flags&PR_CACHEFILE)
symbol->array[mixed++]=prog->name;
prog=prog->next;
}
*(struct fplSymbol **)*tags=symbol;
#ifdef DEBUG
CheckMem(scr, symbol);
CheckMem(scr, symbol->array);
#endif
break;
/* ---------------- new from V10: --------------------- */
case FPLSEND_RESULT:
resultcode = (long *)(*tags); /* long to store result in! */
break;
case FPLSEND_IS_FILE_CACHED:
if(resultcode) {
prog=scr->programs;
while(prog) {
if(prog->name && !strcmp(prog->name, (uchar *)(*tags))) {
*resultcode = TRUE;
break;
}
prog=prog->next;
}
*resultcode = FALSE;
}
break;
/* --------------------------------------------------- */
case FPLSEND_GETSYMBOL_FREE:
#ifdef DEBUG
CheckMem(scr, (void *)(*tags));
CheckMem(scr, ((struct fplSymbol *)*tags)->array);
#endif
FREE(((struct fplSymbol *)*tags)->array);
FREE(*tags);
break;
#if defined(AMIGA) && defined(SHARED)
case FPLSEND_GETSTACKSIZE:
*(long *)*tags=scr->stack_size;
break;
case FPLSEND_GETSTACKUSED:
*(long *)*tags=GetStackUsed(scr);
break;
#endif
case FPLSEND_SETPROGNAME:
if(scr->prog) {
if(scr->prog->name)
FREEA(scr->prog->name);
STRDUPA(scr->prog->name, *tags);
}
break;
case FPLSEND_SETFILENAMEGET:
if(scr->prog) {
if(*tags)
scr->prog->flags|=PR_FILENAMEFLUSH;
else
scr->prog->flags&=~PR_FILENAMEFLUSH;
}
break;
case FPLSEND_GETVERSION:
*(long *)(*tags) = FPL_VERSION; /* as defined in FPL.h */
break;
case FPLSEND_GETREVISION:
*(long *)(*tags) = FPL_REVISION; /* as defined in FPL.h */
break;
}
tags++;
}
if(!msg.type)
/*
* There is no message to send. Everything we had to do is done!
*/
return(FPL_OK);
if(msg.type==FPLMSG_RETURN && (msg.flags == FPLMSG_FLG_STRING)) {
if(len<0)
if(data)
len=strlen(data);
if(!len || !data)
/* this really is a zero length string! */
msg.message[0]=NULL;
else {
if(!fplallocstring) {
/* we have to duplicate the data */
GETMEM(msg.message[0], len+sizeof(struct fplStr));
string=msg.message[0];
string->len=len;
string->alloc=len;
memcpy(string->string, data, len); /* copy string! */
string->string[string->len]=CHAR_ASCII_ZERO; /* zero terminate */
} else {
/* the data was sent as fplAllocString() data! */
string= (struct fplStr *)(data - offsetof(struct fplStr, string));
string->len=len;
string->string[string->len]=CHAR_ASCII_ZERO; /* zero terminate */
SwapMem(scr, string, MALLOC_DYNAMIC); /* convert */
msg.message[0]=string;
}
}
}
CALL(SendMessage(scr, &msg));
return(ret);
}
/*********************************************************************
*
* fplConvertString()
*
* Returns the number of characters converted from the FPL format
* string to the binary sting stored in a buffer.
*
* The output string always get zero terminated!
*
*****/
long PREFIX
fplConvertString(AREG(0) struct Data *scr,
AREG(1) uchar *string,
AREG(2) uchar *buffer)
{
long prg=scr->prg;
uchar *text=scr->text;
long line;
uchar *base;
long a;
long number=0;
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_FUNCTION, 500, "fplConvertString");
#endif
if(!scr->prog) {
/*
* There is no program at the moment!
* create a pseudo program for now!
*/
scr->prog=(struct Program *)MALLOC(sizeof(struct Program));
if(!scr->prog)
return(0); /* no characters in output! */
scr->prog->flags|=PR_TEMPORARY;
}
base=scr->prog->name;
line=scr->prog->lines;
/*
if(*string==CHAR_QUOTATION_MARK)
string++;
*/
scr->prg=1;
scr->text=string;
scr->prog->lines=1;
scr->prog->name=NULL; /* we have no file ID yet! */
while(/* *scr->text!=CHAR_QUOTATION_MARK && */
!ReturnChar(scr, &a, TRUE)) { /* returns non-zero when an ascii zero is
found! */
*buffer++=a;
number++;
}
*buffer=CHAR_ASCII_ZERO;
scr->prg=prg;
scr->text=text;
scr->prog->lines=line;
scr->prog->name=base;
if(scr->prog->flags&PR_TEMPORARY) {
FREE(scr->prog);
scr->prog=NULL;
}
return(number);
}
/**********************************************************************
*
* GetSymbols();
*
* Allocates a structure and data, which is a list of name pointers
* that match the flag parameter.
*
*******/
static ReturnCode REGARGS
GetSymbols(struct Data *scr,
long flag1,
long flag2,
struct fplSymbol **get)
{
long i;
long num;
struct Identifier *ident;
struct fplSymbol *symbol;
for(i=num=0; i<scr->hash_size; i++) {
ident=scr->hash[i];
while(ident) {
if(ident->flags&flag1 && ident->flags&flag2)
num++;
ident=ident->next;
}
}
GETMEM(symbol, sizeof(struct fplSymbol));
symbol->num=num;
GETMEM(symbol->array, sizeof(uchar *)*symbol->num);
for(i=num=0; i<scr->hash_size; i++) {
ident=scr->hash[i];
while(ident) {
if(ident->flags&flag1 && ident->flags&flag2)
symbol->array[num++]=ident->name;
ident=ident->next;
}
}
*get=symbol;
#ifdef DEBUG
CheckMem(scr, symbol->array);
#endif
return(FPL_OK);
}
/**********************************************************************
*
* SendMessage();
*
* Add a member to the message queue. Allocate a new struct and copy the
* data of from second parameter message pointer.
*
******/
static ReturnCode INLINE
SendMessage(struct Data *scr,
struct fplMsg *msg)
{
struct fplMsg *NewMsg, *ptr;
GETMEM(NewMsg, sizeof(struct fplMsg));
*NewMsg=*msg; /* copy all data from source */
/* Queue the message: */
if(ptr=scr->msg)
ptr->prev=NewMsg; /* this message becomes the previous for this */
scr->msg=NewMsg;
NewMsg->next=ptr;
NewMsg->prev=NULL; /* no previous, this is first! */
return(FPL_OK);
}
/**********************************************************************
*
* DeleteMessage();
*
* Deletes specified or current message (NULL).
*
*****/
ReturnCode REGARGS
DeleteMessage(struct Data *scr,
struct fplMsg *msg)
{
struct fplMsg *ptr=scr->msg;
if(msg)
ptr=msg;
if(ptr) {
if(ptr->next)
ptr->next->prev=ptr->prev; /* redirect next message's prev pointer */
else if(!ptr->prev) /* is this the only message? */
scr->msg=NULL;
if(ptr->prev)
ptr->prev->next=ptr->next; /* redirect previous message's next pointer */
FREE(ptr); /* free message */
}
return(FPL_OK);
}
/**********************************************************************
*
* GetMessage()
*
* Returns the first message of the requested type in the pointer
* in the third argument!
*
****/
ReturnCode REGARGS
GetMessage(struct Data *scr,
uchar type,
struct fplMsg **get)
{
struct fplMsg *msg=scr->msg;
while(*get=msg) {
if(msg->type==type)
break;
msg=msg->next;
}
return(FPL_OK);
}
/**********************************************************************
*
* GetProgram();
*
* Whenever we want to access a program in the program list, we do it
* using this function. This enables heavy program swapping capabilities.
* Programs that are not being used can be flushed from memory and brought
* back whenever we need it!
*
******/
ReturnCode REGARGS
GetProgram(struct Data *scr,
struct Program *prog)
{
struct fplArgument *arg;
ReturnCode ret;
struct fplMsg *msg;
struct fplStr *string;
if(!prog->program) {
/*
* The program is not currently in memory. Get it!
*/
if(prog->flags&PR_FILENAMEFLUSH) {
/*
* We know that the program is simply to load from the file the program
* name specifies.
*/
CALL(ReadFile(scr, prog->name, prog));
} else {
/*
* We must ask user for information!
*/
GETMEM(arg, sizeof(struct fplArgument));
arg->ID=FPL_FILE_REQUEST;
arg->key=(void *)scr;
arg->argv=(void **)&prog->name;
arg->argc=1;
ret=InterfaceCall(scr, arg, scr->function);
FREE(arg);
if(ret)
return ret;
GetMessage(scr, FPLMSG_PROGRAM, &msg);
if(!msg) {
GetMessage(scr, FPLMSG_RETURN, &msg);
if(!msg || ((msg->flags&FPLMSG_FLG_BITS) != FPLMSG_FLG_STRING))
/*
* No kind of proper answer could be found!
* Dead end failure!
*/
return FPLERR_INTERNAL_ERROR;
string=(struct fplStr *)msg->message[0];
ret = ReadFile(scr, string->string, prog);
FREE(msg->message[0]); /* we don't need this anymore! */
if(ret)
return ret;
} else {
/*
* User supplied us with a memory pointer to the program again!
*/
prog->program= (uchar *)msg->message[0];
prog->flags|=PR_USERSUPPLIED;
}
DeleteMessage(scr, msg);
}
} /* else
we already have it loaded! */
prog->running++;
return(FPL_OK);
}
/**********************************************************************
*
* LeaveProgram();
*
* If we leave one program, call this. If any flush is to be done, this
* will perform that!
*
******/
ReturnCode REGARGS
LeaveProgram(struct Data *scr,
struct Program *prog)
{
struct fplArgument *arg;
ReturnCode ret;
struct fplMsg *msg;
prog->running--;
if(prog->program && !prog->running && prog->flags&PR_FLUSH_NOT_IN_USE) {
/*
* The program is there and no one is using it!
* flush it if we want to!
*/
if(prog->flags&PR_USERSUPPLIED) {
/*
* This program is supplied by the external program. We cannot
* free the memory, only tell our father that freeing is OK...
*/
GETMEM(arg, sizeof(struct fplArgument));
arg->ID=FPL_FLUSH_FILE;
arg->key=(void *)scr;
arg->argv=(void **)&prog->name;
arg->argc=1;
CALL(InterfaceCall(scr, arg, scr->function));
FREE(arg);
GetMessage(scr, FPLMSG_CONFIRM, &msg);
/*
* We require a {FPLSEND_CONFIRM, TRUE} message from the user before we
* flush the user supplied function! Simply ignore implementing any
* answer to this message if we never want to flush user supplied
* functions.
*/
if(msg && msg->message[0])
/* If we got a "OK" message! */
prog->program=NULL;
if(msg)
DeleteMessage(scr, msg);
} else {
/*
* The memory occupied by this program is our business.
* Swap the memory first to be sure we know the kind of it!
*/
SwapMem(scr, prog->program, MALLOC_DYNAMIC);
FREE(prog->program);
prog->program=NULL; /* to visualize the clearing of this program! */
}
}
return(FPL_OK);
}
static long INLINE
Exists(struct Data *scr,
uchar *name,
long check)
{
ReturnCode ret;
struct Identifier *ident;
GetIdentifier(scr, name, &ident);
if(check && ident) {
switch(tolower(check)) {
case EXISTS_FUNCTION:
ret = ident->flags&FPL_FUNCTION;
break;
case EXISTS_INTEGER:
ret = ident->flags&FPL_INT_VARIABLE;
break;
case EXISTS_STRING:
ret = ident->flags&FPL_STRING_VARIABLE;
break;
case EXISTS_VARIABLE:
ret = ident->flags&FPL_VARIABLE;
break;
}
}
else
ret = ident?TRUE:FALSE;
return ret;
}
/**********************************************************************
*
* int functions(struct fplArgument *);
*
* This function handles the internal functions. *EXACTLY* the same way
* external processes handles their functions!!! :-)
*
*****/
ReturnCode REGARGS
functions(struct fplArgument *arg)
{
struct Expr *val;
unsigned long inttags[]={FPLSEND_INT, 0, FPLSEND_DONE};
unsigned long strtags[]={FPLSEND_STRING, 0, FPLSEND_STRLEN, 0, FPLSEND_DONE};
long base;
ReturnCode ret;
struct Data *scr=(struct Data *)arg->key;
struct fplStr *string;
long prg;
long line;
long virprg;
uchar *virfile;
uchar *text;
/* uchar *file; */
long len; /* length of the string */
register long col; /* the column parameter */
switch(arg->ID) {
case FNC_ABS:
inttags[1]= ABS((long)arg->argv[0]);
CALL(Send(arg->key, inttags));
break;
case FNC_ITOC:
prg=(long)arg->argv[0]&255;
text=(uchar *)&line; /* we just need 2 bytes to play with in peace! */
text[1]='\0';
text[0]=prg;
strtags[1]=(long)text;
strtags[3]=1;
CALL(Send(scr, strtags));
break;
case FNC_JOINSTR:
string=NULL;
for(prg=0; prg<arg->argc; prg++) {
CALL(StrAssign((struct fplStr *) ((uchar *)arg->argv[prg]-
offsetof(struct fplStr, string)),
scr, &string, TRUE));
}
if(string) {
strtags[1]=(unsigned long)string->string;
strtags[3]=string->len;
CALL(Send(scr, strtags));
FREE(string);
}
break;
case FNC_ITOA:
case FNC_LTOSTR:
base=(arg->argc<2?10:(long)arg->argv[1]);
CALL(Ltostr(scr, &string, base, (long)arg->argv[0]));
strtags[1]=(unsigned long)string->string;
strtags[3]=string->len;
CALL(Send(scr, strtags));
FREE(string);
break;
case FNC_ATOI:
case FNC_STRTOL:
base=(arg->argc<2?10:(long)arg->argv[1]);
inttags[1]= Strtol((uchar *)arg->argv[0], base, &text);
CALL(Send(scr, inttags));
break;
case FNC_EVAL:
prg=scr->prg;
text=scr->text;
line=scr->prog->lines;
virprg=scr->virprg;
virfile=scr->virfile;
scr->virprg=1;
scr->virfile=NULL;
scr->text=(uchar *)arg->argv[0];
scr->prg=scr->prog->lines=1;
GETMEM(val, sizeof(struct Expr));
CALL(Expression(val, scr, CON_GROUNDLVL|CON_END|CON_NUM, NULL));
inttags[1]=val->val.val;
FREE(val);
scr->prg=prg;
scr->text=text;
scr->prog->lines=line;
scr->virprg=virprg;
scr->virfile=virfile;
CALL(Send(scr, inttags));
break;
case FNC_INTERPRET:
prg=scr->prg;
text=scr->text;
line=scr->prog->lines;
/* file=scr->prog->name; */
virprg=scr->virprg;
virfile=scr->virfile;
scr->virprg=1;
scr->virfile=NULL;
scr->interpret=NULL; /* nothing recursive here, no no! */
scr->prg=1;
scr->text=(uchar *)arg->argv[0];
scr->prog->lines=1;
/* scr->prog->name=NULL; */ /* we have no file name! */
GETMEM(val, sizeof(struct Expr));
ret=Script(scr, val, SCR_NORMAL, NULL);
inttags[1]=val->val.val;
FREE(val);
if(ret) {
/*
* Check if the error occurred somewhere in the real program
* or if it was within the argument. If within argument, we
* set back the previous program pointer, otherwise not.
*/
for(base=0;base<line;base++)
if(scr->text>(&scr->prog->program)[base] &&
scr->text<((&scr->prog->program)[base]+
strlen((&scr->prog->program)[base])))
break;
if(base==line) {
scr->prg=prg;
scr->text=text;
scr->prog->lines=line;
/* scr->prog->name=file; */
}
return(ret);
}
scr->prg=prg;
scr->text=text;
scr->prog->lines=line;
/* scr->prog->name=file; */
scr->virprg=virprg;
scr->virfile=virfile;
CALL(Send(arg->key, inttags));
break;
case FNC_RENAME:
{
struct Identifier *ident;
GetIdentifier(scr, (uchar *)arg->argv[0], &ident);
if(!ident || ident->flags&FPL_KEYWORD) {
/* not found or found keyword, fail! */
inttags[1] = FPLERR_IDENTIFIER_NOT_FOUND;
}
else {
if(((char *)arg->argv[1])[0])
inttags[1] = RenameIdentifier(scr, ident, arg->argv[1]);
else
inttags[1] = DelIdentifier(scr, NULL, ident);
}
CALL(Send(arg->key, inttags));
}
break;
case FNC_STRCMP:
case FNC_STRICMP:
/*
* strcmp() with strings that can include a zero byte must use
* memcmp(), but that also takes a third length argument which
* must never be larger than the smallest of the two compared
* strings!
*/
line = MIN(FPL_STRING_LENGTH(arg, 0), FPL_STRING_LENGTH(arg, 1)); /* len */
if(FNC_STRCMP == arg->ID)
base = memcmp(arg->argv[0], arg->argv[1], line);
else
base = my_memicmp(arg->argv[0], arg->argv[1], line);
if(!base && FPL_STRING_LENGTH(arg, 0) != FPL_STRING_LENGTH(arg, 1)) {
/* similar strings after 'line' characters */
/*
* The strings are of different length.
*/
base = ((uchar *)arg->argv[0])[line] -
(FPL_STRING_LENGTH(arg, 1)>line?
((uchar *)arg->argv[1])[line] : 0 );
if(!base) {
/* only possible since FPL strings can hold zeroes! */
base = 256; /* not possible in regular C */
}
}
inttags[1]=base;
CALL(Send(scr, inttags));
break;
case FNC_SUBSTR:
len=FPL_STRING_LENGTH(arg, 0);
col=(long)arg->argv[1];
if(col>len || col<0) {
; /* we can't get any string! */
} else {
len-=col; /* Maximum length we can get */
strtags[3]=((long)arg->argv[2]>len?len:(long)arg->argv[2]); /* strlen */
strtags[1]=(long) arg->argv[0]+col; /* return string from here */
CALL(Send(scr, strtags));
}
break;
case FNC_STRLEN:
inttags[1]=FPL_STRING_LENGTH(arg, 0);
CALL(Send(scr, inttags));
break;
case FNC_STRNCMP:
case FNC_STRNICMP:
/*
* strncmp() with strings that can include a zero byte must use
* memcmp(), that also takes a third length argument which
* must never be larger than the smallest of the two compared
* strings or the number specified!
*/
if(FNC_STRNCMP == arg->ID) {
inttags[1]=
memcmp(arg->argv[0], arg->argv[1],
MIN3((long)arg->argv[2],
FPL_STRING_LENGTH(arg, 0), FPL_STRING_LENGTH(arg, 1)));
}
else {
inttags[1]=
my_memicmp(arg->argv[0], arg->argv[1],
MIN3((long)arg->argv[2],
FPL_STRING_LENGTH(arg, 0), FPL_STRING_LENGTH(arg, 1)));
}
CALL(Send(scr, inttags));
break;
case FNC_STRSTR:
case FNC_STRISTR:
/*
* strstr() should compare two memory regions, like a memmem()!
* Code an own!
*/
base = FPL_STRLEN(arg->argv[0]);
line = FPL_STRLEN(arg->argv[1]);
text = (uchar *)arg->argv[0];
/*
* Addition from FPL version 9:
* starting search column in third parameter!
*/
if(arg->argc>2) {
if((int)arg->argv[2] < base) {
text+=(int)arg->argv[2];
base-=(int)arg->argv[2];
}
else {
/* tried to start searching outside the string! */
line = 1; /* to make a not-found return code */
base = 0;
}
}
if(line && base) {
if(FNC_STRSTR == arg->ID) {
/* Case sensitive */
while(base-->=line) {
if(!memcmp(text, (uchar *)arg->argv[1], line)) {
line=0;
break;
}
text++;
}
}
else {
/* Case insensitive */
while(base-->=line) {
if(!my_memicmp(text, (uchar *)arg->argv[1], line)) {
line=0;
break;
}
text++;
}
}
}
inttags[1]=line?-1:text-(uchar *)arg->argv[0];
/* OLD ONE:
text=(uchar *)strstr((uchar *)arg->argv[0], (uchar *)arg->argv[1]);
inttags[1]=text?text-(uchar *)arg->argv[0]:-1;
*/
CALL(Send(scr, inttags));
break;
case FNC_SPRINTF:
{
static unsigned long tags[]={
FPLSEND_STRING, 0,
FPLSEND_STRLEN, 0,
FPLSEND_DONTCOPY_STRING, TRUE,
FPLSEND_DONE
};
string = NULL;
CALL(Sprintf(scr, &string, arg->argv[0], arg->argv, arg->format,
arg->argc));
if(string) {
tags[1] = (long)string->string;
tags[3] = string->len;
CALL(Send(scr, tags));
}
}
break;
case FNC_SSCANF:
{
inttags[1] =
Sscanf(scr,
(uchar *)arg->argv[0],
(uchar *)arg->argv[1],
arg->argc,
arg->argv,
arg->format);
CALL(Send(scr, inttags));
}
break;
case FNC_EXISTS:
inttags[1] = Exists(scr,
(uchar *)arg->argv[0],
arg->argc>1?(long)arg->argv[1]:0);
CALL( Send(scr, inttags) );
break;
#if defined(AMIGA)
case FNC_OPENLIB:
CALL(OpenLib(scr,
(uchar *)arg->argv[0], /* name */
(long)arg->argv[1], /* version */
(long *)&inttags[1], /* funclib result */
0)); /* normal 'soft' open */
CALL(Send(scr, inttags));
break;
case FNC_CLOSELIB:
CALL(CloseLib(scr,
(uchar *)arg->argv[0], /* name */
0, /* 'soft' close */
(long *)&inttags[1])); /* funclib result */
CALL(Send(scr, inttags));
break;
case FNC_DEBUG:
if(arg->argc) {
if(!(int)arg->argv[0]) {
scr->flags&=~FPLDATA_DEBUG_MODE; /* switch off debug mode */
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_EXIT, 500, NULL);
#endif
}
else {
scr->flags|=FPLDATA_DEBUG_MODE; /* switch on debug mode */
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_START, 500, NULL);
#endif
}
}
else {
inttags[1]=scr->flags&FPLDATA_DEBUG_MODE?1:0; /* return status */
CALL(Send(scr, inttags));
}
break;
#endif
}
return(FPL_OK);
}
#if defined(AMIGA)
ReturnCode REGARGS
OpenLib(struct Data *scr,
uchar *lib, /* funclib name */
long version, /* funclib version */
long *retvalue, /* funclib return code */
uchar flags)
{
struct MyLibrary *library;
struct Library *DOSBase;
BPTR seglist;
uchar *command;
uchar *cmd;
struct FuncList *namelist=scr->funclibs;
uchar *name;
ReturnCode ret;
struct fplStr *string;
struct ExecBase *SysBase = *(struct ExecBase **)4;
library = (struct MyLibrary *)getreg(REG_A6);
DOSBase = library->ml_DosBase;
GETMEM(command, FPLLIB_MAXSPACE);
while(namelist) {
if(!strcmp(namelist->name, lib)) {
namelist->opens++;
return FPL_OK; /* this funclib is already opened */
}
namelist = namelist->next;
}
cmd = command;
strcpy(command, FPLLIB_SOURCE);
strcpy(command+strlen(FPLLIB_SOURCE), lib);
seglist = LoadSeg(command); /* load the command! */
if(seglist) {
strcpy(command, FPLLIB_OPENCMD);
command += strlen(FPLLIB_OPENCMD);
CALL(Ltostr(scr, &string, 10, (long)scr));
strcpy(command, string->string);
command[string->len]= ' '; /* pad with a single space */
command+=string->len+1;
FREE(string);
CALL(Ltostr(scr, &string, 10, version));
strcpy(command, string->string);
command[string->len]= '\n'; /* add newline */
command[string->len+1]= '\0'; /* zero terminate */
FREE(string);
if(SysBase->SoftVer<36) {
/* V33 solution! */
uchar *segment = BADDR(seglist);
int (*func)();
#pragma msg 147 ignore
func = segment + 4; /* generates warning */
#pragma msg 147 warning
putreg(REG_A0, (long)cmd);
putreg(REG_D0, strlen(cmd));
#pragma msg 154 ignore
*retvalue = (func)(); /* generates warning */
#pragma msg 154 warning
} else /* version 36 or up! */
*retvalue = RunCommand(seglist, 4000, cmd, strlen(cmd));
UnLoadSeg( seglist );
} else {
/* we failed loading the command! */
*retvalue = FUNCLIB_LOAD;
}
FREE(cmd);
if(!*retvalue) {
GETMEMA(namelist, sizeof(struct FuncList));
STRDUPA(name, lib);
namelist->name = name;
namelist->opens = 1;
namelist->flags = flags;
namelist->next = scr->funclibs;
scr->funclibs = namelist;
}
return FPL_OK;
}
ReturnCode REGARGS
CloseLib(struct Data *scr,
uchar *lib, /* funclib name or NULL for all */
long flags, /* options */
long *retvalue) /* funclib return code */
{
struct MyLibrary *library;
struct Library *DOSBase;
struct FuncList *namelist=scr->funclibs;
struct FuncList *prevlist=NULL;
struct FuncList *next;
uchar *command;
uchar *cmd;
ReturnCode ret;
struct fplStr *string;
BPTR seglist;
struct ExecBase *SysBase = *(struct ExecBase **)4;
library = (struct MyLibrary *)getreg(REG_A6);
DOSBase = library->ml_DosBase;
GETMEM(command, FPLLIB_MAXSPACE);
cmd = command;
while(namelist) {
if(namelist->flags&FPLLIB_KEEP && namelist->opens==1) {
/* This funclib is prevented from being 'soft' closed! */
namelist->opens++;
}
if((!lib || !strcmp(namelist->name, lib)) &&
(!--namelist->opens || flags&FPLLIB_FORCE) ) {
/* the funclib _is_ opened! */
strcpy(command, FPLLIB_SOURCE);
strcpy(command+strlen(FPLLIB_SOURCE), lib);
seglist = LoadSeg(command); /* load the command! */
if(seglist) {
strcpy(command, FPLLIB_CLOSECMD);
command += strlen(FPLLIB_CLOSECMD);
CALL(Ltostr(scr, &string, 10, (long)scr));
strcpy(command, string->string);
command[string->len]= '\n'; /* add newline */
command[string->len+1]= '\0'; /* zero terminate */
FREE(string);
if(SysBase->SoftVer<36) {
/* V33 solution! */
uchar *segment = BADDR(seglist);
int (*func)();
#pragma msg 147 ignore
func = segment + 4; /* generates warning */
#pragma msg 147 warning
putreg(REG_A0, (long)cmd);
putreg(REG_D0, strlen(cmd));
#pragma msg 154 ignore
*retvalue = (func)(); /* generates warning */
#pragma msg 154 warning
} else /* version 36 or up! */
*retvalue = RunCommand(seglist, 4000, cmd, strlen(cmd));
UnLoadSeg( seglist );
} else {
/* we failed loading the command! */
*retvalue = FUNCLIB_LOAD;
}
if(!*retvalue) {
next = namelist->next;
if(prevlist) /* was there a previous funclib in the list? */
prevlist->next=next; /* point it to the next in the list */
else
scr->funclibs = next; /* point the origin to the next */
FREEA(namelist->name); /* free name space */
FREEA(namelist); /* free struct */
namelist = next;
continue;
}
}
prevlist = namelist;
namelist = namelist->next;
}
FREE(cmd);
return FPL_OK;
}
#endif
/**********************************************************************
*
* fplLtostr()
*
* Frontend to the FPL Ltostr() function to be used by anyone! The returned
* string *must* be freed using the fplFreeString() function!
*
****/
uchar * PREFIX
fplLtostr(AREG(0) struct Data *scr,
DREG(0) long base,
DREG(1) long num)
{
ReturnCode ret;
struct fplStr *string;
uchar *retstring=NULL;
#ifdef DEBUGMAIL
DebugMail(scr, MAIL_FUNCTION, 500, (void *)"fplLtostr");
#endif
ret = Ltostr(scr, &string, base, num);
if(FPL_OK == ret) {
SwapMem(scr, string, MALLOC_STATIC); /* turn allocation to static type */
retstring = string->string; /* return string pointer */
}
return retstring;
}
static ReturnCode REGARGS
Ltostr(struct Data *scr,
struct fplStr **string,
long base,
long num)
{
/*
* Convert the integer to string with `any base'-convertions.
*/
extern const uchar upper_digits[];
ReturnCode ret;
static const uchar *digits = upper_digits;
long is_neg=num<0;
long len=0;
uchar buffer[34+sizeof(struct fplStr)];
uchar *bufpoint; /* the accurate position in the buffer */
if(base>strlen(digits)) {
CALL(Warn(scr, FPLERR_OUT_OF_REACH));
num=strlen(digits); /* reset to maximum */
}
num=ABS(num);
buffer[33+sizeof(struct fplStr)]=CHAR_ASCII_ZERO; /* zero byte termination */
bufpoint=&buffer[33+sizeof(struct fplStr)]; /* start digit output position */
if(num) {
while(num>0) {
*--bufpoint= digits[num % base];
num /= base;
len++;
}
if(is_neg) {
*--bufpoint='-';
len++;
}
} else {
*--bufpoint=CHAR_ZERO;
len++;
}
GETMEM(*string, len+sizeof(struct fplStr));
strcpy((*string)->string, bufpoint);
(*string)->len=len;
(*string)->alloc=len;
return(FPL_OK);
}
/**********************************************************************
*
* fplStrtol()
*
* Frontend to the FPL Strtol() function to be used by anyone!
*
****/
long PREFIX
fplStrtol(AREG(0) uchar *string,
DREG(0) long base,
AREG(1) uchar **end)
{
uchar *dummypoint;
if(!end)
end = &dummypoint;
/*
* THIS CAN'T CURRENT CALL DEBUGMAIL SINCE NO struct Data IS USED!!!
*/
return Strtol(string, base, end);
}
/**********************************************************************
*
* Strtol()
*
* String to long integer. Code copied and changed from the GNU libc
* source code package.
*
****/
long REGARGS
Strtol(uchar *nptr,
long base,
uchar **end)
{
uchar negative;
unsigned long cutoff;
unsigned long cutlim;
long i;
uchar *s;
uchar c;
uchar *save;
long overflow;
if (base < 0 || base == 1 || base > 36)
base = 10;
s = nptr;
/* Skip white space. */
while(isspace(*s))
s++;
if (*s == CHAR_ASCII_ZERO)
return (0);
/* Check for a sign. */
else if (*s == CHAR_MINUS) {
negative = 1;
++s;
} else if (*s == CHAR_PLUS) {
negative = 0;
++s;
} else
negative = 0;
if ((base == 16 && s[0] == CHAR_ZERO && UPPER(s[1]) == CHAR_UPPER_X) ||
(base == 2 && s[0] == CHAR_ZERO && UPPER(s[1]) == CHAR_UPPER_B) )
s += 2;
/* If BASE is zero, figure it out ourselves. */
if (base == 0)
if (*s == '0') {
switch(UPPER(s[1])) {
case CHAR_UPPER_X:
s += 2;
base = 16;
break;
case CHAR_UPPER_B:
s += 2;
base = 2;
break;
default:
base = 8;
break;
}
} else
base = 10;
/* Save the pointer so we can check later if anything happened. */
save = s;
cutoff = ULONG_MAX / (unsigned long int) base;
cutlim = ULONG_MAX % (unsigned long int) base;
overflow = 0;
i = 0;
for (c = *s; c; c = *++s) {
if (isdigit(c))
c -= '0';
else if (isalpha(c))
c = UPPER(c) - CHAR_UPPER_A + 10;
else
break;
if (c >= base)
break;
/* Check for overflow. */
if (i > cutoff || (i == cutoff && c > cutlim))
overflow = 1;
else {
i *= (unsigned long int) base;
i += c;
}
}
*end=s; /* this is the end position of the number */
/* Check if anything actually happened. */
if (s == save)
return (0);
/* Check for a value that is within the range of
`unsigned long int', but outside the range of `long int'. */
if (i > (negative ?
- (unsigned long int) LONG_MIN :
(unsigned long int) LONG_MAX))
overflow = 1;
if (overflow)
return negative ? LONG_MIN : LONG_MAX;
/* Return the result of the appropriate sign. */
return (negative ? - i : i);
}
/*****************************************************************************
*
* my_memicmp()
*
* This makes a case insensitive memcmp() with the very same parameters.
*
*********/
long REGARGS my_memicmp(uchar *s1, uchar *s2, long len)
{
long pos=0;
long result;
while(pos < len) {
result = tolower(s1[pos]) - tolower(s2[pos]);
if(result)
return result;
pos++;
}
return 0;
}
ReturnCode REGARGS
StringExpr(struct Expr *val, /* original string -> new */
struct Data *scr) /* standard */
{
ReturnCode ret;
struct fplStr *whole;
CALL(Eat(scr)); /* scan white spaces */
if(CHAR_PLUS == scr->text[0]) {
GETMEM(whole, sizeof(struct fplStr));
memset(whole, 0, sizeof(struct fplStr));
/* put string in new string variable */
CALL(StrAssign(val->val.str, scr, &whole, 1));
do {
scr->text++; /* skip the '+' */
CALL(Expression(val, scr, CON_STRING, NULL));
/* append string to that new variable */
CALL(StrAssign(val->val.str, scr, &whole, 1));
if(!(val->flags&FPL_NOFREE) && val->val.str)
FREE(val->val.str);
} while(CHAR_PLUS == scr->text[0]);
val->val.str = whole; /* get the string info! */
val->flags&=~FPL_NOFREE; /* free this, yes! */
}
return FPL_OK;
}